#!/usr/bin/python3
from pypinyin import Style, lazy_pinyin
import os
import shutil

"""
在指定文件夹拆分归纳，包括子文件夹
可选先根据后缀名归纳，后缀名文件夹文件数如果大于某个指定的数然后，则该后缀名文件夹中再根据拼音首字母归纳，例外和数字都归纳到'#'文件夹，
会自动跳过符号寻找第一个数字、字母或汉字
文件名或文件夹名重复将自己覆盖，请谨慎操作
"""


def addToDict(dir_dict, dir_path, file_path):
    if dir_path in dir_dict:
        dir_dict[dir_path].append(file_path) 
    else:
        dir_dict[dir_path] = [file_path]


def splitByExtension(path):
    dir_dict = {}
    list = os.listdir(path)
    for file in list:
        file_path = os.path.join(path, file)
        if os.path.isfile(file_path):
            ext = os.path.splitext(file)[-1].upper().replace('.','')
            if not ext:
                ext = '#'
            dir_path = os.path.join(path,ext)
            addToDict(dir_dict, dir_path, file_path)
    return dir_dict


def splitByPinyin(path):
    dir_dict = {}
    list = os.listdir(path)
    for p in list:
        file_path = os.path.join(path, p)
        try:
            list = lazy_pinyin(os.path.splitext(p)[0], style=Style.FIRST_LETTER)
            if len(list) != 0:
                is_distinguished = False
                for str in list:
                    for char in str:
                        if char.encode('utf-8').isalpha():
                            dir_path = os.path.join(path,char.upper())
                            addToDict(dir_dict, dir_path, file_path)
                            is_distinguished = True
                            break
                        if char.encode('utf-8').isdigit():
                            dir_path = os.path.join(path,'#')
                            addToDict(dir_dict, dir_path, file_path)
                            is_distinguished = True
                            break
                    if is_distinguished:
                        break
                if not is_distinguished:
                    dir_path = os.path.join(path, '#')
                    addToDict(dir_dict, dir_path, file_path)
            else:
                dir_path = os.path.join(path,'#')
                addToDict(dir_dict, dir_path, file_path)
        except Exception as e:
            print(e)
    return dir_dict


def moveByDict(dir_dict):
    """
    value 列表中的所有文件移动到路径为key的文件夹中
    """
    try:
        for key in dir_dict:
            if not os.path.exists(key):
                os.mkdir(key)
            for file in dir_dict[key]:
                if file.upper() == key.upper():
                    continue
                target_file = os.path.join(key, os.path.basename(file))
                if os.path.exists(target_file):
                    if os.path.isfile(target_file):
                        os.remove(target_file)
                    else:
                        shutil.rmtree(target_file)
                    print(f'Rewrite same name file or directory: "{target_file}".')
                print(f'move "{file}" to "{key}".')
                shutil.move(file, key)
    except Exception as e:
        print('move failed :{}'.format(e))


def run(dir, only_pinyin=True, min_num=100):
    """
    main run
    """
    if not os.path.exists(dir) or not os.path.isdir(dir):
        print(f'dir {dir} is not exists.')
        return
    
    if only_pinyin:
        moveByDict(splitByPinyin(dir))
        print('Pack "{}" only by Pinyin finished.'.format(dir))
    else:
        extension_dict = splitByExtension(dir)
        moveByDict(extension_dict)
        for key in extension_dict:
            # 只归纳文件数大于min_num的后缀
            if len(extension_dict[key]) > min_num:
                moveByDict(splitByPinyin(key))
        print('Pack "{}" by Extension and Pinyin finished.'.format(dir))


if __name__ == "__main__":
    """ 属性配置"""
    # 拆分文件夹列表
    dirs = ['']
    # 不进行后缀名分类，只进行拼音分类，后缀分类对文件夹无效
    only_pinyin = True
    # 后缀分类后进行拼音分类的最小文件数
    min_num = 100
    print('开始运行:')
    for dir in dirs:
        run(dir, only_pinyin, min_num)